package sys_serv

import (
	"strconv"
	"strings"
	"ubt-gin-admin/app/api/model/sys_mod"
	"ubt-gin-admin/app/pkg/db"
	"ubt-gin-admin/app/pkg/enums"
)

type sysMenu struct{}

var SysMenuServ = sysMenu{}

// Add 新增菜单
func (s *sysMenu) Add(req *sys_mod.SysMenuSaveReq) (string, string) {
	sqlStr := `INSERT INTO sys_menu(menu_name, menu_code, parent_id, sort, url, icon, showed, remarks, states, add_time, upd_time) 
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 1, EXTRACT(epoch FROM NOW()), EXTRACT(epoch FROM NOW()))`
	return db.CudData(sqlStr, req.MenuName, req.MenuCode, req.ParentId, req.Sort, req.Url, req.Icon, req.Showed, req.Remarks)
}

// Exists 判断菜单编码是否存在
func (s *sysMenu) Exists(req *sys_mod.SysMenuExtVo) bool {
	sqlStr := "SELECT menu_id FROM sys_menu WHERE states=1 AND menu_code=$1"
	param := make([]any, 0)
	param = append(param, req.MenuCode)
	if req.MenuId != "" {
		sqlStr += " AND menu_id!=$2"
		param = append(param, req.MenuId)
	}
	if _, _, data := db.GetOne(sqlStr, param...); len(data) == 0 {
		return false
	}
	return true
}

// Update 修改菜单
func (s *sysMenu) Update(req *sys_mod.SysMenuSaveReq) (string, string) {
	sqlStr := "UPDATE sys_menu SET menu_name=$1, menu_code=$2, parent_id=$3, sort=$4, url=$5, icon=$6, showed=$7, remarks=$8, upd_time=EXTRACT(epoch FROM NOW()) WHERE menu_id=$9"
	return db.CudData(sqlStr, req.MenuName, req.MenuCode, req.ParentId, req.Sort, req.Url, req.Icon, req.Showed, req.Remarks, req.MenuId)
}

// Deletes 删除菜单
func (s *sysMenu) Deletes(req *sys_mod.SysMenuDelsReq) (string, string) {
	var (
		// param 数据库表操作的参数数组
		param []any
		// idList 编号数组
		idList []string
		// q 拼接SQL的点位符字符串，如$1, $2……
		q string
		// 索引序号
		n = 0
	)
	// 将字符串转换成数组
	idArr := strings.Split(req.MenuIds, ",")
	// 获取所有的菜单编号
	_, _, menuList := db.GetAll("SELECT menu_id, parent_id FROM sys_menu WHERE states=1 ORDER BY menu_code")
	// 递归遍历每个菜单下的子菜单及子孙菜单，最后返回给idList编号数组
	for _, curId := range idArr {
		idList = append(idList, curId)
		idList = s.getIds(menuList, curId, idList)
	}
	// 拼接SQL
	for _, curId := range idList {
		n++
		q += "$" + strconv.Itoa(n) + ","
		param = append(param, curId)
	}
	q = q[:len(q)-1]
	sqlStr := "UPDATE sys_menu SET states=2, upd_time=EXTRACT(epoch FROM NOW()) WHERE menu_id IN (" + q + ")"
	return db.CudData(sqlStr, param...)
}

// getIds 递归遍历获取子级菜单编号
func (s *sysMenu) getIds(list []map[string]any, id any, newList []string) []string {
	for _, item := range list {
		if id == item["parentId"] {
			newList = append(newList, item["menuId"].(string))
			newList = s.getIds(list, item["menuId"], newList)
		}
	}
	return newList
}

// One 获取菜单详情
func (s *sysMenu) One(menuId string) (string, string, map[string]any) {
	sqlStr := "SELECT a.menu_id, a.menu_name, a.menu_code, a.icon, a.url, a.showed, a.parent_id, a.sort, " +
		"(CASE WHEN a.parent_id='111111111111111111111' THEN '一级菜单' ELSE b.menu_name END) AS parent_name, " +
		"(CASE WHEN a.parent_id='111111111111111111111' THEN '10000000' ELSE b.menu_code END) AS parent_code, " +
		"a.remarks, a.states, a.add_time, a.upd_time " +
		"FROM sys_menu a " +
		"LEFT JOIN sys_menu b ON b.states=1 AND a.parent_id=b.menu_id " +
		"WHERE a.menu_id=$1"
	return db.GetOne(sqlStr, menuId)
}

// List 获取菜单树状列表
func (s *sysMenu) List() (string, string, any) {
	code, _, list := db.GetAll("SELECT menu_id, menu_name, menu_code, parent_id, sort, url, icon, showed FROM sys_menu WHERE states=1 ORDER BY sort")
	if code == enums.Succeed.Code {
		var newList []map[string]any
		var level uint8 = 1
		for _, item := range list {
			if item["parentId"] == "111111111111111111111" {
				item["level"] = level
				newList = append(newList, item)
				newList = s.sortChildMenu(list, item["menuId"], newList, level)
			}
		}
		return enums.Succeed.Code, enums.Succeed.Msg, newList
	}
	return enums.NoData.Code, enums.NoData.Msg, nil
}

// sortChildMenu 将菜单按树状排序
func (s *sysMenu) sortChildMenu(list []map[string]any, id any, newList []map[string]any, level uint8) []map[string]any {
	level++
	for _, item := range list {
		if id == item["parentId"] {
			item["level"] = level
			newList = append(newList, item)
			newList = s.sortChildMenu(list, item["menuId"], newList, level)
		}
	}
	return newList
}

// Select 获取菜单树状列表
func (s *sysMenu) Select(menuCodes string, kind uint8) (string, string, any) {
	var (
		sqlStr string
		code   string
		list   []map[string]any
	)
	if kind == 3 {
		sqlStr = "SELECT menu_id, menu_name, menu_code, parent_id, sort, false AS chked FROM sys_menu WHERE states=1 ORDER BY sort"
		code, _, list = db.GetAll(sqlStr)
	} else {
		sqlStr = "SELECT menu_id, menu_name, menu_code, parent_id, sort, false AS chked FROM sys_menu WHERE states=1 AND $1 LIKE '%'||menu_code||'%' ORDER BY sort"
		code, _, list = db.GetAll(sqlStr, menuCodes)
	}
	if code == enums.Succeed.Code {
		var newList []map[string]any
		var level uint8 = 1
		for _, item := range list {
			if item["parentId"] == "111111111111111111111" {
				item["level"] = level
				newList = append(newList, item)
				newList = s.sortChildMenu(list, item["menuId"], newList, level)
			}
		}
		return enums.Succeed.Code, enums.Succeed.Msg, newList
	}
	return enums.NoData.Code, enums.NoData.Msg, nil
}

// Sort 获取菜单数量，用于排序
func (s *sysMenu) Sort(parentId string) (string, string, map[string]any) {
	sqlStr := "SELECT COUNT(1)+1 AS nums FROM sys_menu WHERE states=1 AND parent_id=$1"
	return db.GetOne(sqlStr, parentId)
}

// Tree 获取菜单树状列表
func (s *sysMenu) Tree() (string, string, any) {
	code, _, list := db.GetAll("SELECT menu_id sel_id, menu_name sel_name, menu_code sel_code, parent_id FROM sys_menu WHERE states=1 ORDER BY sort")
	if code == enums.Succeed.Code {
		var level uint8 = 0
		tree := s.buildTree("111111111111111111111", list, level)
		return enums.Succeed.Code, enums.Succeed.Msg, tree
	}
	return enums.NoData.Code, enums.NoData.Msg, nil
}

func (s *sysMenu) buildTree(parentId any, list []map[string]any, level uint8) []map[string]any {
	tree := make([]map[string]any, 0)
	level++
	for _, child := range list {
		if parentId == child["parentId"] {
			children := s.buildTree(child["selId"], list, level)
			child["level"] = level
			child["children"] = children
			tree = append(tree, child)
		}
	}
	return tree
}

// Menu 获取菜单树状菜单
func (s *sysMenu) Menu(menuCodes string) (string, string, any) {
	code, _, list := db.GetAll("SELECT menu_id sel_id, menu_name, url, parent_id, icon, true AS exted FROM sys_menu WHERE states=1 AND showed=1 AND $1 LIKE '%'||menu_code||'%' ORDER BY sort", menuCodes)
	if code == enums.Succeed.Code {
		var level uint8 = 0
		tree := s.buildTree("111111111111111111111", list, level)
		return enums.Succeed.Code, enums.Succeed.Msg, tree
	}
	return enums.NoData.Code, enums.NoData.Msg, nil
}
